﻿using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Zeus.Mvc.Controllers;
namespace Nereus.Zeus.Mvc
{
    using Attributes;
    using Power;
    public class ZeusMvcBuilder : DefaultNBuilder
    {
        private Dictionary<string, Type> _allResultTypes;
        private object _analysisResultTypeLock = new object();

        public override IEnumerable<INClassContent> BuildClassContent(string[] assemblyPathArray)
        {
            var _allNClass = new List<NClassContent>();
            var nAssemblies = new List<Assembly>();
            if (assemblyPathArray == null || assemblyPathArray.Length <= 0)
            {
                var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            }
            else
            {
                nAssemblies.AddRange(assemblyPathArray.Select(x => Assembly.Load(x)));
            }
            //filter
            var allTypes = new List<Type>();
            nAssemblies.ForEach(assembly => allTypes.AddRange(assembly.GetTypes().Where(type => !type.FullName.StartsWith("Microsoft") && !type.FullName.StartsWith("System"))));

            foreach (var item in allTypes)
            {
                if (_allResultTypes == null || _allResultTypes.Count() <= 0)
                {
                    _allResultTypes = new Dictionary<string, Type>();
                    lock (_analysisResultTypeLock)
                    {
                        if (_allResultTypes == null || _allResultTypes.Count() <= 0)
                        {
                            var body = NereusUtil.AnalysisHeaderAndBody(item.Name, "Result", 0);
                            if (!string.IsNullOrWhiteSpace(body))
                            {
                                _allResultTypes.Add(body, item);
                            }
                        }
                    }
                }
            }

            foreach (var type in allTypes)
            {
                if (!type.IsAbstract && typeof(ZeusController).IsAssignableFrom(type))
                {
                    var noNereus = type.GetCustomAttributes<NonNereusAttribute>();
                    if (noNereus.Count() > 0)
                    {
                        continue;
                    }
                    var nClassContent = new NClassContent();
                    var nClassAttribute = type.GetNAttribute<NClassAttribute>();
                    if (nClassAttribute != null)
                    {
                        nClassContent.Code = nClassAttribute.Code;
                        nClassContent.Description = nClassAttribute.Description;
                        nClassContent.Name = nClassAttribute.Name;
                    }
                    else
                    {
                        nClassContent.Code = type.Name.Replace("Controller", string.Empty).Replace("controller", string.Empty);
                        nClassContent.Description = string.Empty;
                        nClassContent.Name = $"{nClassContent.Code}";
                    }
                    nClassContent.Methods = BuildMethodContent(type);

                    if (nClassContent.Methods != null && nClassContent.Methods.Count() > 0)
                    {
                        _allNClass.Add(nClassContent);
                    }
                }
            }
            return _allNClass.ToArray();
        }

        public override IEnumerable<INMethodContent> BuildMethodContent(Type classType)
        {
            var classMethods = classType.GetMethods();
            var nMethods = new List<NMethodContent>();
            foreach (var method in classMethods)
            {
                var nonNereusAttribute = method.GetNAttribute<NonNereusAttribute>();
                if (nonNereusAttribute != null)
                {
                    continue;
                }
                var nMethodAttribute = method.GetNAttribute<NMethodAttribute>();
                var route = method.GetCustomAttributes<RouteAttribute>();

                if (nMethodAttribute != null)
                {
                    if (!nMethodAttribute.Enable)
                    {
                        continue;
                    }
                    var uri = nMethodAttribute.Uri;
                    var arguments = method.GetParameters();
                    if (route != null && route.Count() > 0)
                    {
                        uri = route.First().Template;
                    }
                    var nAction = new NMethodContent()
                    {
                        ActionCode = string.IsNullOrWhiteSpace(nMethodAttribute.Code) ? method.Name : nMethodAttribute.Code,
                        ArgumentProperties = BuildPropertyContent(nMethodAttribute.Argument ?? arguments[0].ParameterType),
                        Description = nMethodAttribute.Description,
                        Method = nMethodAttribute.Method,
                        Name = nMethodAttribute.Name,
                        ResultExplain = nMethodAttribute.ResultExplain,
                        ResultProperties = BuildPropertyContent(nMethodAttribute.Result),
                        Uri = uri
                    };
                    nMethods.Add(nAction);
                }
                else if (route != null && route.Count() > 0)
                {
                    Type resultType = null;
                    if (_allResultTypes.ContainsKey(method.Name))
                    {
                        resultType = _allResultTypes[method.Name];
                    }
                    var arguments = method.GetParameters();
                    var nAction = new NMethodContent()
                    {
                        ActionCode = method.Name,
                        ArgumentProperties = arguments.Count() > 0 ? BuildPropertyContent(arguments[0].ParameterType) : null,
                        Description = string.Empty,
                        Method = "POST",
                        Name = $"{method.Name}",
                        ResultExplain = string.Empty,
                        ResultProperties = resultType != null ? BuildPropertyContent(resultType) : null,
                        Uri = route.First().Template
                    };
                    nMethods.Add(nAction);
                }
            }
            return nMethods;
        }

    }
}
